package com.dkts.oil.test;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;

import java.io.*;
import java.util.*;

public class AISTrajectoryProcessor {

    private static final double MAX_TIME_DIFF = 60.0; // 最大时间差，单位：秒
    private static final double MAX_DISTANCE_DIFF = 500.0; // 最大距离差，单位：米

    public static void main(String[] args) throws Exception {
        File csvFile = new File("C:\\Users\\heyou\\Documents\\WeChat Files\\wxid_86da35bc9zvi21\\FileStorage\\File\\2025-05\\c9a6717b7d2f5293cf7cd2ed05a0494c_2e2437ef9cd58c0d39af05569deeb4be_8.csv");  // 替换成实际路径
        Reader reader = new FileReader(csvFile);

        // 解析CSV文件
        CSVParser parser = CSVFormat.DEFAULT
                .withFirstRecordAsHeader()
                .parse(reader);

        Map<String, List<CSVRecord>> mmsiMap = new HashMap<>();

        // 按MMSI分组
        for (CSVRecord record : parser) {
            String mmsi = record.get("mmsi");
            if (!mmsiMap.containsKey(mmsi)) {
                mmsiMap.put(mmsi, new ArrayList<>());
            }
            mmsiMap.get(mmsi).add(record);
        }

        // 创建GeoJSON处理类
        ObjectMapper mapper = new ObjectMapper();
        for (Map.Entry<String, List<CSVRecord>> entry : mmsiMap.entrySet()) {
            List<CSVRecord> records = entry.getValue();
            if (records.size() < 2) continue;  // 如果轨迹少于2个点，则跳过

            // 轨迹分段
            List<List<CSVRecord>> segments = segmentTrajectory(records);

            // 为每个分段生成GeoJSON文件
            for (int i = 0; i < segments.size(); i++) {
                List<CSVRecord> segment = segments.get(i);
                File mmsiDir = new File("output/" + entry.getKey());
                if (!mmsiDir.exists()) {
                    mmsiDir.mkdirs();
                }

                // 创建GeoJSON文件
                File geoJsonFile = new File(mmsiDir, "segment_" + (i + 1) + ".geojson");
                FileWriter writer = new FileWriter(geoJsonFile);

                // 写入GeoJSON内容
                writeGeoJson(segment, mapper, writer);
                writer.close();
            }
        }
        System.out.println("GeoJSON文件已生成！");
    }

    // 按时间分段轨迹

    // 计算两个地理点之间的距离，单位：米
    private static double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
        final int R = 6371000; // 地球半径，单位：米
        double latDistance = Math.toRadians(lat2 - lat1);
        double lonDistance = Math.toRadians(lon2 - lon1);
        double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2) +
                Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
                        Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        return R * c; // 返回结果，单位：米
    }

    // 计算两个轨迹点之间的时间差，单位秒
    private static double calculateTimeDiff(CSVRecord prev, CSVRecord current) {
        String prevTime = prev.get("time");
        String currentTime = current.get("time");

        // 假设时间格式为"yyyy-MM-dd HH:mm:ss"
        try {
            long prevTimestamp = Long.parseLong(prevTime);
            long currentTimestamp = Long.parseLong(currentTime);
            return (currentTimestamp - prevTimestamp);
        } catch (NumberFormatException e) {
            return 0;
        }
    }

    // 按时间和距离分段轨迹
    private static List<List<CSVRecord>> segmentTrajectory(List<CSVRecord> records) {
        List<List<CSVRecord>> segments = new ArrayList<>();
        List<CSVRecord> currentSegment = new ArrayList<>();
        currentSegment.add(records.get(0));

        for (int i = 1; i < records.size(); i++) {
            CSVRecord prevRecord = records.get(i - 1);
            CSVRecord currentRecord = records.get(i);

            double timeDiff = calculateTimeDiff(prevRecord, currentRecord);
            double distanceDiff = calculateDistance(
                    Double.parseDouble(prevRecord.get("lat")),
                    Double.parseDouble(prevRecord.get("lon")),
                    Double.parseDouble(currentRecord.get("lat")),
                    Double.parseDouble(currentRecord.get("lon"))
            );

            if (timeDiff <= MAX_TIME_DIFF && distanceDiff <= MAX_DISTANCE_DIFF) {
                currentSegment.add(currentRecord);
            } else {
                segments.add(new ArrayList<>(currentSegment));
                currentSegment.clear();
                currentSegment.add(currentRecord);
            }
        }

        if (!currentSegment.isEmpty()) {
            segments.add(currentSegment);
        }
        return segments;
    }

    // 处理轨迹点，进行圆弧插值处理，并且检查距离
    private static List<InterpolatedRecord> interpolateTrajectory(List<CSVRecord> records) {
        List<InterpolatedRecord> interpolatedRecords = new ArrayList<>();

        for (int i = 0; i < records.size() - 1; i++) {
            CSVRecord currentRecord = records.get(i);
            CSVRecord nextRecord = records.get(i + 1);

            double timeDiff = calculateTimeDiff(currentRecord, nextRecord);
            double distanceDiff = calculateDistance(
                    Double.parseDouble(currentRecord.get("lat")),
                    Double.parseDouble(currentRecord.get("lon")),
                    Double.parseDouble(nextRecord.get("lat")),
                    Double.parseDouble(nextRecord.get("lon"))
            );

            if (timeDiff > 1 && distanceDiff > MAX_DISTANCE_DIFF) {
                // 如果时间差大，且距离差大，进行插值处理
                interpolatedRecords.addAll(interpolateArc(currentRecord, nextRecord, timeDiff));
            }
        }
        return interpolatedRecords;
    }


    // 圆弧插值
    private static List<InterpolatedRecord> interpolateArc(CSVRecord start, CSVRecord end, double timeDiff) {
        List<InterpolatedRecord> interpolatedRecords = new ArrayList<>();

        // 计算插值点数量，基于时间差
        int pointsToInsert = (int) (timeDiff / 60);  // 每60秒插值一次

        for (int i = 1; i <= pointsToInsert; i++) {
            double interpolatedLon = Double.parseDouble(start.get("lon")) + (Double.parseDouble(end.get("lon")) - Double.parseDouble(start.get("lon"))) * i / (pointsToInsert + 1);
            double interpolatedLat = Double.parseDouble(start.get("lat")) + (Double.parseDouble(end.get("lat")) - Double.parseDouble(start.get("lat"))) * i / (pointsToInsert + 1);

            // 创建插值记录
            InterpolatedRecord interpolatedRecord = new InterpolatedRecord(start.get("mmsi"), start.get("time"), interpolatedLat, interpolatedLon);
            interpolatedRecords.add(interpolatedRecord);
        }
        return interpolatedRecords;
    }

    // 将轨迹段写入GeoJSON文件
    private static void writeGeoJson(List<CSVRecord> segment, ObjectMapper mapper, FileWriter writer) throws IOException {
        ObjectNode featureCollection = mapper.createObjectNode();
        featureCollection.put("type", "FeatureCollection");
        ArrayNode features = mapper.createArrayNode();

        ObjectNode feature = mapper.createObjectNode();
        feature.put("type", "Feature");

        // 构建 LineString
        ObjectNode geometry = mapper.createObjectNode();
        geometry.put("type", "LineString");
        ArrayNode coordinates = mapper.createArrayNode();
        for (CSVRecord record : segment) {
            ArrayNode coord = mapper.createArrayNode();
            coord.add(Double.parseDouble(record.get("lon")));
            coord.add(Double.parseDouble(record.get("lat")));
            coordinates.add(coord);
        }
        geometry.set("coordinates", coordinates);
        feature.set("geometry", geometry);

        // 属性信息
        ObjectNode properties = mapper.createObjectNode();
        properties.put("mmsi", segment.get(0).get("mmsi"));
        properties.put("start_time", segment.get(0).get("time"));
        properties.put("end_time", segment.get(segment.size() - 1).get("time"));

        feature.set("properties", properties);
        features.add(feature);

        featureCollection.set("features", features);

        mapper.writerWithDefaultPrettyPrinter().writeValue(writer, featureCollection);
    }
}
